package com.zhonghui.common.eshopService.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.eshop.service.Impl.BaseServiceImpl;
import com.zhonghui.common.eshopDomain.StoreCombination;
import com.zhonghui.common.eshopDomain.StorePink;
import com.zhonghui.common.eshopDto.PinkUserDto;
import com.zhonghui.common.eshopEnum.OrderInfoEnum;
import com.zhonghui.common.eshopEnum.PinkEnum;
import com.zhonghui.common.eshopMapper.StorePinkMapper;
import com.zhonghui.common.eshopService.StoreCombinationService;
import com.zhonghui.common.eshopService.StorePinkService;
import com.zhonghui.modlules.cart.eshopDomain.StoreCart;
import com.zhonghui.modlules.cart.eshopService.StoreCartService;
import com.zhonghui.modlules.cart.eshopVo.StoreCartQueryVo;
import com.zhonghui.modlules.order.eshopDomain.StoreOrder;
import com.zhonghui.modlules.order.eshopService.StoreOrderService;
import com.zhonghui.modlules.order.eshopVo.StoreOrderQueryVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Transactional(
        propagation = Propagation.SUPPORTS,
        readOnly = true,
        rollbackFor = {Exception.class}
)
public class StorePinkServiceImpl extends BaseServiceImpl<StorePinkMapper, StorePink> implements StorePinkService {
    @Autowired
    private StoreOrderService storeOrderService;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private StorePinkMapper storePinkMapper;
    @Autowired
    private StoreCombinationService combinationService;
    @Autowired
    private StoreCartService storeCartService;

    @Override
    public int pinkIngCount(Long id) {
        return ((LambdaQueryChainWrapper) ((LambdaQueryChainWrapper) this.lambdaQuery().
                eq( StorePink::getStatus, OrderInfoEnum.PINK_STATUS_1.getValue() )
                .eq( StorePink::getId, id ))
                )
                .count();
    }


    public void createPink(StoreOrderQueryVo order) {
        StoreCombination storeCombination = (StoreCombination)this.combinationService.getById(order.getCombinationId());
        order = this.storeOrderService.handleOrder(order);
        StoreCart storeCart = (StoreCart)this.storeCartService.getById(order.getCartId());
        int pinkCount = this.storePinkMapper.selectCount((Wrapper) Wrappers.<StorePink>lambdaQuery().eq(StorePink::getOrderId, order.getOrderId()));
        if (pinkCount <= 0) {
            if (storeCombination != null) {
                StorePink storePink = StorePink.builder().uid(order.getUid()).orderId(order.getOrderId()).orderIdKey(order.getId()).totalNum(order.getTotalNum()).totalPrice(order.getPayPrice()).build();
                List<StoreCartQueryVo> cartInfo = order.getCartInfo();
                Iterator var7 = cartInfo.iterator();

                while(var7.hasNext()) {
                    StoreCartQueryVo queryVo = (StoreCartQueryVo)var7.next();
                    storePink.setCid(queryVo.getCombinationId());
                    storePink.setPid(queryVo.getProductId());
                }

                Date stopTime = DateUtil.offsetHour(new Date(), storeCombination.getEffectiveTime());
                storePink.setPeople(storeCombination.getPeople());
                storePink.setStopTime(stopTime);
                storePink.setUniqueId(storeCart.getProductAttrUnique());
                if (order.getPinkId() > 0L) {
                    if (this.getIsPinkUid(order.getPinkId(), order.getUid())) {
                        return;
                    }

                    storePink.setKId(order.getPinkId());
                    storePink.setStopTime((Date)null);
                    this.save(storePink);
                    PinkUserDto pinkUserDto = this.getPinkMemberAndPinK(storePink);
                    StorePink pinkT = pinkUserDto.getPinkT();
                    if (OrderInfoEnum.PINK_STATUS_1.getValue().equals(pinkT.getStatus())) {
                        if (pinkUserDto.getCount() == 0) {
                            this.pinkComplete(pinkUserDto.getUidAll(), pinkUserDto.getIdAll(), order.getUid(), pinkT);
                        } else {
                            this.pinkFail(pinkUserDto.getPinkAll(), pinkT, PinkEnum.PINK_BOOL_0.getValue());
                        }
                    }
                } else {
                    this.save(storePink);
                    StoreOrder storeOrder = new StoreOrder();
                    storeOrder.setPinkId(storePink.getId());
                    storeOrder.setId(order.getId());
                    this.storeOrderService.updateById(storeOrder);
                    String redisKey = String.valueOf( StrUtil.format("{}{}", new Object[]{"pink:cancel:", storePink.getId()}));
                    long expireTime = storeCombination.getEffectiveTime().longValue() * 3600L;
                    this.redisTemplate.opsForValue().set(redisKey, "1", expireTime, TimeUnit.SECONDS);
                }
            }

        }
    }


    public boolean getIsPinkUid(Long id, Long uid) {
        int count = lambdaQuery().eq(StorePink::getIsRefund, OrderInfoEnum.PINK_REFUND_STATUS_0.getValue()).eq(StorePink::getUid, uid).and((i) -> {
            LambdaQueryWrapper var10000 = (LambdaQueryWrapper)(i.eq(StorePink::getKId, id)).or().eq(StorePink::getId, id);
        }).count();
        return count > 0;
    }
    private PinkUserDto getPinkMemberAndPinK(StorePink pink) {
        List<StorePink> pinkAll = null;
        StorePink pinkT = null;
        if (pink.getKId() > 0L) {
            pinkAll = this.getPinkMember(pink.getKId());
            pinkT = this.getPinkUserOne(pink.getKId());
        } else {
            pinkAll = this.getPinkMember(pink.getId());
            pinkT = pink;
        }

        List<Long> idAll = (List)pinkAll.stream().map(StorePink::getId).collect( Collectors.toList());
        List<Long> uidAll = (List)pinkAll.stream().map(StorePink::getUid).collect(Collectors.toList());
        idAll.add(pinkT.getId());
        uidAll.add(pinkT.getUid());
        int count = pinkT.getPeople() - (pinkAll.size() + 1);
        return PinkUserDto.builder().pinkAll(pinkAll).pinkT(pinkT).idAll(idAll).uidAll(uidAll).count(count).build();
    }

    private List<StorePink> getPinkMember(Long kid) {
        return ((LambdaQueryChainWrapper)(lambdaQuery().eq(StorePink::getKId, kid)).eq(StorePink::getIsRefund, OrderInfoEnum.PINK_REFUND_STATUS_0.getValue()).orderByAsc(StorePink::getId)).list();
    }

    private StorePink getPinkUserOne(Long id) {
        return (StorePink)((LambdaQueryChainWrapper)this.lambdaQuery().eq(StorePink::getId, id)).one();
    }

    private int pinkComplete(List<Long> uidAll, List<Long> idAll, Long uid, StorePink pinkT) {
        boolean pinkStatus = this.getPinkStatus(idAll);
        int pinkBool = PinkEnum.PINK_BOOL_0.getValue();
        if (pinkStatus) {
            LambdaQueryWrapper<StorePink> wrapper = new LambdaQueryWrapper();
            wrapper.in(StorePink::getId, idAll);
            StorePink storePink = new StorePink();
            storePink.setStopTime(new Date());
            storePink.setStatus(OrderInfoEnum.PINK_STATUS_2.getValue());
            this.update(storePink, wrapper);
            if (uidAll.contains(uid)) {
                pinkBool = PinkEnum.PINK_BOOL_1.getValue();
            }
        }

        return pinkBool;
    }
    private int pinkFail(List<StorePink> pinkAll, StorePink pinkT, int pinkBool) {
        Date now = new Date();
        if (DateUtil.compare(pinkT.getStopTime(), now) < 0) {
            pinkBool = PinkEnum.PINK_BOOL_MINUS_1.getValue();
            pinkAll.add(pinkT);
            Iterator var5 = pinkAll.iterator();

            while(var5.hasNext()) {
                StorePink storePink = (StorePink)var5.next();
                this.storeOrderService.orderApplyRefund("", "", "拼团时间超时", storePink.getOrderId(), storePink.getUid());
                this.orderPinkFailAfter(pinkT.getUid(), storePink.getId());
            }
        }

        return pinkBool;
    }

    private boolean getPinkStatus(List<Long> idAll) {
        int count = ((LambdaQueryChainWrapper)(lambdaQuery().in(StorePink::getId, idAll)).eq(StorePink::getIsRefund, OrderInfoEnum.PINK_REFUND_STATUS_1.getValue())).count();
        return count == 0;
    }
    private void orderPinkFailAfter(Long uid, Long pid) {
        StorePink storePink = new StorePink();
        LambdaQueryWrapper<StorePink> wrapper = new LambdaQueryWrapper();
        wrapper.eq(StorePink::getId, pid);
        storePink.setStatus(OrderInfoEnum.PINK_STATUS_3.getValue());
        storePink.setStopTime(new Date());
        this.storePinkMapper.update(storePink, wrapper);
        LambdaQueryWrapper<StorePink> wrapperT = new LambdaQueryWrapper();
        wrapperT.eq(StorePink::getKId, pid);
        this.storePinkMapper.update(storePink, wrapperT);
    }

}
